using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Domain.Entities;
using SumerCoreDevOps.Infrastructure.Data;
using SumerCoreDevOps.Infrastructure.Distributed;

namespace SumerCoreDevOps.Infrastructure.Scheduling;

/// <summary>
/// 主节点管理器，负责管理多个主节点的注册、发现和健康检查
/// </summary>
public class MasterNodeManager : IHostedService, IDisposable
{
    private readonly IDistributedCoordinator _coordinator;
    private readonly FreeSQLProvider _dbProvider;
    private readonly ILogger<MasterNodeManager> _logger;
    private readonly string _masterId;
    private readonly string _host;
    private readonly int _tcpPort;
    private readonly int _apiPort;
    private Timer? _heartbeatTimer;
    private Timer? _cleanupTimer;
    private bool _disposed;

    public string MasterId => _masterId;

    public MasterNodeManager(
        IDistributedCoordinator coordinator,
        FreeSQLProvider dbProvider,
        ILogger<MasterNodeManager> logger,
        string? masterId = null,
        string host = "localhost",
        int tcpPort = 9090,
        int apiPort = 5000)
    {
        _coordinator = coordinator ?? throw new ArgumentNullException(nameof(coordinator));
        _dbProvider = dbProvider ?? throw new ArgumentNullException(nameof(dbProvider));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _masterId = masterId ?? GenerateMasterId();
        _host = host;
        _tcpPort = tcpPort;
        _apiPort = apiPort;
    }

    private static string GenerateMasterId()
    {
        var hostName = Environment.MachineName;
        var uniqueId = Guid.NewGuid().ToString("N")[..8];
        return $"{hostName}-{uniqueId}";
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Starting MasterNodeManager for master: {MasterId}", _masterId);

        try
        {
            // 注册主节点到 Redis
            await _coordinator.RegisterMasterAsync(_masterId, _host, _tcpPort, _apiPort, cancellationToken);

            // 注册或更新主节点到数据库
            await RegisterOrUpdateInDatabaseAsync(cancellationToken);

            // 启动心跳定时器 (每30秒)
            _heartbeatTimer = new Timer(
                HeartbeatCallback,
                null,
                TimeSpan.Zero,
                TimeSpan.FromSeconds(30));

            // 启动清理定时器 (每60秒)
            _cleanupTimer = new Timer(
                CleanupCallback,
                null,
                TimeSpan.FromSeconds(60),
                TimeSpan.FromSeconds(60));

            _logger.LogInformation("MasterNodeManager started successfully for master: {MasterId}", _masterId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to start MasterNodeManager for master: {MasterId}", _masterId);
            throw;
        }
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Stopping MasterNodeManager for master: {MasterId}", _masterId);

        try
        {
            // 停止定时器
            if (_heartbeatTimer != null)
            {
                await _heartbeatTimer.DisposeAsync();
                _heartbeatTimer = null;
            }

            if (_cleanupTimer != null)
            {
                await _cleanupTimer.DisposeAsync();
                _cleanupTimer = null;
            }

            // 注销主节点
            await _coordinator.UnregisterMasterAsync(_masterId, cancellationToken);

            // 更新数据库状态
            await UpdateDatabaseStatusAsync(false, cancellationToken);

            _logger.LogInformation("MasterNodeManager stopped successfully for master: {MasterId}", _masterId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error stopping MasterNodeManager for master: {MasterId}", _masterId);
        }
    }

    private void HeartbeatCallback(object? state)
    {
        _ = Task.Run(async () =>
        {
            try
            {
                await _coordinator.UpdateMasterHeartbeatAsync(_masterId);
                await UpdateDatabaseStatusAsync(true);
                _logger.LogDebug("Master heartbeat updated: {MasterId}", _masterId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating master heartbeat: {MasterId}", _masterId);
            }
        });
    }

    private void CleanupCallback(object? state)
    {
        _ = Task.Run(async () =>
        {
            try
            {
                await CleanupOfflineMastersAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error cleaning up offline masters");
            }
        });
    }

    private async Task RegisterOrUpdateInDatabaseAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            var db = _dbProvider.Orm;
            var existingMaster = await db.Select<MasterNode>()
                .Where(m => m.MasterId == _masterId)
                .FirstAsync(cancellationToken);

            if (existingMaster == null)
            {
                // 新建主节点记录
                var masterNode = new MasterNode
                {
                    MasterId = _masterId,
                    Host = _host,
                    TcpPort = _tcpPort,
                    ApiPort = _apiPort,
                    IsOnline = true,
                    LastHeartbeatTime = DateTime.Now
                };

                await db.Insert(masterNode).ExecuteAffrowsAsync(cancellationToken);
                _logger.LogInformation("Registered new master in database: {MasterId}", _masterId);
            }
            else
            {
                // 更新现有主节点
                existingMaster.Host = _host;
                existingMaster.TcpPort = _tcpPort;
                existingMaster.ApiPort = _apiPort;
                existingMaster.IsOnline = true;
                existingMaster.LastHeartbeatTime = DateTime.Now;

                await db.Update<MasterNode>()
                    .SetSource(existingMaster)
                    .ExecuteAffrowsAsync(cancellationToken);

                _logger.LogInformation("Updated existing master in database: {MasterId}", _masterId);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to register or update master in database: {MasterId}", _masterId);
            throw;
        }
    }

    private async Task UpdateDatabaseStatusAsync(bool isOnline, CancellationToken cancellationToken = default)
    {
        try
        {
            var db = _dbProvider.Orm;
            await db.Update<MasterNode>()
                .Set(m => m.IsOnline, isOnline)
                .Set(m => m.LastHeartbeatTime, DateTime.Now)
                .Where(m => m.MasterId == _masterId)
                .ExecuteAffrowsAsync(cancellationToken);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update database status for master: {MasterId}", _masterId);
        }
    }

    private async Task CleanupOfflineMastersAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            // 从 Redis 获取在线主节点
            var onlineMasters = await _coordinator.GetOnlineMastersAsync(cancellationToken);
            var onlineMasterIds = onlineMasters.Select(m => m.MasterId).ToHashSet();

            // 查询数据库中标记为在线的主节点
            var db = _dbProvider.Orm;
            var dbOnlineMasters = await db.Select<MasterNode>()
                .Where(m => m.IsOnline)
                .ToListAsync(cancellationToken);

            // 标记不在 Redis 中的主节点为离线
            foreach (var master in dbOnlineMasters)
            {
                if (!onlineMasterIds.Contains(master.MasterId))
                {
                    await db.Update<MasterNode>()
                        .Set(m => m.IsOnline, false)
                        .Where(m => m.Id == master.Id)
                        .ExecuteAffrowsAsync(cancellationToken);

                    _logger.LogWarning("Marked master as offline (not in Redis): {MasterId}", master.MasterId);
                }
            }

            // 清理超过5分钟未心跳的主节点
            var timeoutThreshold = DateTime.Now.AddMinutes(-5);
            await db.Update<MasterNode>()
                .Set(m => m.IsOnline, false)
                .Where(m => m.IsOnline && m.LastHeartbeatTime < timeoutThreshold)
                .ExecuteAffrowsAsync(cancellationToken);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during offline masters cleanup");
        }
    }

    /// <summary>
    /// 获取所有在线的主节点（从 Redis）
    /// </summary>
    public async Task<List<MasterInfo>> GetOnlineMastersAsync(CancellationToken cancellationToken = default)
    {
        return await _coordinator.GetOnlineMastersAsync(cancellationToken);
    }

    /// <summary>
    /// 获取所有在线的主节点（从数据库）
    /// </summary>
    public async Task<List<MasterNode>> GetOnlineMastersFromDbAsync(CancellationToken cancellationToken = default)
    {
        var db = _dbProvider.Orm;
        return await db.Select<MasterNode>()
            .Where(m => m.IsOnline)
            .OrderBy(m => m.LastHeartbeatTime)
            .ToListAsync(cancellationToken);
    }

    /// <summary>
    /// 选择一个主节点（负载均衡）
    /// </summary>
    public async Task<MasterInfo?> SelectMasterAsync(CancellationToken cancellationToken = default)
    {
        var masters = await GetOnlineMastersAsync(cancellationToken);

        if (masters.Count == 0)
        {
            _logger.LogWarning("No online masters available for selection");
            return null;
        }

        // 简单的轮询策略，选择最早心跳的主节点（假设负载最低）
        var selectedMaster = masters
            .OrderBy(m => m.LastHeartbeat)
            .FirstOrDefault();

        if (selectedMaster != null)
        {
            _logger.LogDebug("Selected master: {MasterId} at {Host}:{TcpPort}",
                selectedMaster.MasterId, selectedMaster.Host, selectedMaster.TcpPort);
        }

        return selectedMaster;
    }

    public void Dispose()
    {
        if (_disposed)
        {
            return;
        }

        _heartbeatTimer?.Dispose();
        _cleanupTimer?.Dispose();
        _disposed = true;
    }
}
